using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Reflection;
using System.Windows.Forms;

namespace OpenComposite.Base.Designer
{
	public class SelectionFrame : IDisposable
	{
		#region Initialization
		static SelectionFrame()
		{
			_cornerPen = new Pen(Color.Black);

			_cornerEnabledBrush = new SolidBrush(Color.White);
			_cornerDisabledBrush = new SolidBrush(Color.LightGray);
		}
		public SelectionFrame(DesignerControl selectedCtrl)
		{
			_selectedCtrl = selectedCtrl;

			init();
		}
		private void init()
		{
			bSuspendRepaint = true;
			this.DesignerViewControl = _selectedCtrl.DesignerViewControl;
			_selectedCtrl.SelectionFrame = this;
			_pathSelection = new GraphicsPath();
			_pathIndicator = new GraphicsPath();

			_bDisposed = false;
			_resizeSidesAllowed = _selectedCtrl.ResizableSides;

			_rectsAllowedCorners = new List<Rectangle>();
			_rectsDisabledCorners = new List<Rectangle>();

			_ptMouseDown = Point.Empty;
			_szChange = Size.Empty;
			_rectPaint = Rectangle.Empty;
			_regionMouseOver = null;

			if ( _selectedCtrl is Route ) {
				_selectionPen = new Pen(new HatchBrush(HatchStyle.Percent20, Color.Gray, Color.Transparent), 7);
				generateRouteFrame();
			} else {
				_selectionPen = new Pen(Color.Gray, 1.0f);
				_selectionPen.DashStyle = DashStyle.Dot;
				generateSymbolFrame();
			}

			_selectedCtrl.LocationChanged += new EventHandler(_selectedControl_LocationChanged);
			_selectedCtrl.SizeChanged += new EventHandler(_selectedControl_SizeChanged);
			_selectedCtrl.ParentChanged += new EventHandler(_selectedCtrl_ParentChanged);
			_selectedCtrl.Removed += new EventHandler(_selectedCtrl_Removed);
			bSuspendRepaint = false;
		}

		#endregion

		#region Public Members

		#region Properties

		public Rectangle Bounds
		{
			get { return _bounds; }
		}

		public DesignerControl SelectedControl
		{
			get { return _selectedCtrl; }
		}
		public DesignerViewControl DesignerViewControl
		{
			get { return _designerView; }
			set { _designerView = value; }
		}

		public ResizeSides AllowedResizeSides
		{
			get { return _resizeSidesAllowed; }
			set {
				if ( _resizeSidesAllowed != value ) {
					_resizeSidesAllowed = value;
					this.Refresh();
				}
			}
		}

		internal DesignerStatus Status
		{
			get { return this.DesignerViewControl.Status; }
		}
		#endregion

		#region Events
		#endregion

		#region Methods

		public void InvokeMouseMove(MouseEventArgs e)
		{
			OnMouseMove(e);
		}
		public void InvokeMouseDown(MouseEventArgs e)
		{
			OnMouseDown(e);
		}
		public void InvokeMouseUp(MouseEventArgs e)
		{
			OnMouseUp(e);
		}
		
		public virtual void Paint(PaintEventArgs pe)
		{
			if ( _bDisposed )
				return;

			SmoothingMode sm = pe.Graphics.SmoothingMode;
			pe.Graphics.SmoothingMode = SmoothingMode.None;

			// paint selection frame
			if ( _pathSelection != null && _pathSelection.PointCount > 0 )
				pe.Graphics.DrawPath(_selectionPen, _pathSelection);

			// paint disabled corners
			if ( _rectsDisabledCorners != null && _rectsDisabledCorners.Count > 0 ) {
				pe.Graphics.FillRectangles(_cornerDisabledBrush, _rectsDisabledCorners.ToArray());
				pe.Graphics.DrawRectangles(_cornerPen, _rectsDisabledCorners.ToArray());
			}
			// paint resize rectangles
			if ( _rectsAllowedCorners.Count > 0 ) {
				pe.Graphics.FillRectangles(
					( this.SelectedControl.CanResize ? _cornerEnabledBrush : _cornerDisabledBrush ),
					_rectsAllowedCorners.ToArray());
				pe.Graphics.DrawRectangles(_cornerPen, _rectsAllowedCorners.ToArray());
			}

			// paint resize/move frame
			if ( this.DesignerViewControl.Status.CurrentMouseMoveMode == MouseMoveMode.Resize ||
				 this.DesignerViewControl.Status.CurrentMouseMoveMode == MouseMoveMode.Move ) {
				if ( _pathIndicator != null && _selectionPen != null )
					pe.Graphics.DrawPath(_selectionPen, _pathIndicator);
			}

			pe.Graphics.SmoothingMode = sm;
		}

		public Point PointToDesignerView(Point p)
		{
			if ( this.SelectedControl.Parent == null )
				return p;
			else {
				p.Offset(this.SelectedControl.Parent.Location);
				return this.SelectedControl.Parent.PointToDesignerView(p);
			}
		}

		public void Invalidate()
		{
			if ( this.DesignerViewControl != null ) {
				RectangleF rf = _pathIndicator.GetBounds();
				Rectangle ri = new Rectangle(Point.Truncate(rf.Location), Size.Ceiling(rf.Size));
				Rectangle rectWithZoom;
				//RectangleF ri2 = _pathSelection.GetBounds();
				ri.Inflate(10, 10);
				rectWithZoom = ApplyZoomFactor(ri);
				//if ( this.SelectedControl.Parent != null )
				//    ri = this.SelectedControl.Parent.RectangleToDesignerView(ri);
				Region r = new Region(rectWithZoom);
				ri.Inflate(-20, -20);
				rectWithZoom = ApplyZoomFactor(ri);
				r.Exclude(rectWithZoom);
				this.DesignerViewControl.MainPanel.Invalidate(r/*ri*/, true);
			}
		}
		public void Refresh()
		{
			Repaint();
		}
		public void Update()
		{
			if ( this.DesignerViewControl != null ) {
				this.DesignerViewControl.Refresh();
			}
		}

		public bool CheckMouseOver(Point location)
		{
			if ( _regionMouseOver == null )
				return _rectPaint.Contains(location);
			else
				return _regionMouseOver.IsVisible(location);
		}
		#region IDisposable Members
		public void Dispose()
		{
			try {
				dispose(_pathSelection);
				dispose(_selectionPen);
				dispose(_pathIndicator);

				_selectedCtrl.SelectionFrame = null;

				if ( _rectsDisabledCorners != null ) {
					_rectsDisabledCorners.Clear();
					_rectsDisabledCorners = null;
				}
				if ( _rectsAllowedCorners != null ) {
					_rectsAllowedCorners.Clear();
					_rectsAllowedCorners = null;
				}
				if ( _rectsResizeable != null ) {
					_rectsResizeable.Clear();
					_rectsResizeable = null;
				}
			} finally {
				_bDisposed = true;
			}
		}
		#endregion

		#endregion

		#endregion

		#region Protected Members

		#region Variables
		protected bool bSuspendRepaint;
		#endregion

		#region Methods

		protected virtual void OnMouseMove(MouseEventArgs e)
		{
			lock ( lockThis ) {
				if ( e.Button == MouseButtons.Right ) {
					//if ( this.Status.CurrentMouseMoveMode == MouseMoveMode.Normal ) {
					//    this.DesignerViewControl.Cursor = Cursors.Default;
					//    this.Status.CurrentMouseMoveMode = MouseMoveMode.DragDrop;
					//    this.Status.DragObject = this.SelectedControl.GetDragObject(e.Location);
					//} else if ( this.Status.CurrentMouseMoveMode == MouseMoveMode.DragDrop ) {
					//    if ( this.Status.MouseOverCtrl != null &&
					//         this.Status.MouseOverCtrl.IsDropAllowed(this.Status.DragObject) )
					//        this.DesignerViewControl.Cursor = Cursors.Default;
					//    else
					//        this.DesignerViewControl.Cursor = Cursors.No;
					//    Repaint();
					//}
				} else {
					bool usegrid = ( this.DesignerViewControl != null &&
									 this.SelectedControl != null && this.SelectedControl.UseGrid );
					if ( this.Status.CurrentMouseMoveMode == MouseMoveMode.Normal &&
						 this.SelectedControl.CanResize ) {
						if ( _rectsResizeable != null ) {
							foreach ( ResizeRectangle rrect in _rectsResizeable ) {
								if ( !rrect.Disabled ) {
									Rectangle r = rrect.Rectangle;
									r.Inflate(2, 2);
									if ( r.Contains(e.X, e.Y) ) {
										setCursor(rrect.State);
										this.Status.CurrentResizeState = rrect.State;
										break;
									} else {
										this.Status.CurrentResizeState = ResizeState.None;
									}
								}
							}
						}
						if ( this.Status.CurrentResizeState == ResizeState.None && this.SelectedControl != null ) {
							setCursor(this.SelectedControl.Cursor);
						}
					} else if ( this.Status.CurrentMouseMoveMode == MouseMoveMode.Resize ) {
						Invalidate();
						if ( this.Status.CurrentResizeState == ResizeState.Right ||
							 this.Status.CurrentResizeState == ResizeState.Left ) {
							_szChange = new Size(e.X - _ptMouseDown.X, 0);
						} else if ( this.Status.CurrentResizeState == ResizeState.Bottom ||
									this.Status.CurrentResizeState == ResizeState.Top ) {
							_szChange = new Size(0, e.Y - _ptMouseDown.Y);
						} else if ( this.Status.CurrentResizeState != ResizeState.None ) {
							_szChange = new Size(e.X - _ptMouseDown.X, e.Y - _ptMouseDown.Y);
						}
						if ( usegrid )
							_szChange = this.DesignerViewControl.SizeToGrid(_szChange);
						//Repaint();
						generateIndicator();
						Invalidate();
						Update();
					} else if ( this.Status.CurrentMouseMoveMode == MouseMoveMode.Move ) {
						Invalidate();
						_szChange = new Size(e.X - _ptMouseDown.X, e.Y - _ptMouseDown.Y);
						if ( usegrid )
							_szChange = this.DesignerViewControl.SizeToGrid(_szChange);
						//Repaint();
						generateIndicator();
						Invalidate();
						Update();
					}
				}
			}
		}
		protected virtual void OnMouseDown(MouseEventArgs e)
		{
			_ptMouseDown = e.Location;
			if ( e.Button == MouseButtons.Left ) {
				if ( this.Status.CurrentResizeState != ResizeState.None ) {
					this.Status.CurrentMouseMoveMode = MouseMoveMode.Resize;
				} else if ( this.SelectedControl.CanMove &&
							this.DesignerViewControl.Cursor == this.SelectedControl.Cursor ) {
					setCursor(Cursors.SizeAll);
					this.Status.CurrentMouseMoveMode = MouseMoveMode.Move;
				}
			}
		}
		protected virtual void OnMouseUp(MouseEventArgs e)
		{
			Size change = _szChange;
			MouseMoveMode mode = this.Status.CurrentMouseMoveMode;
			ResizeState resizestate = this.Status.CurrentResizeState;

			_ptMouseDown = Point.Empty;
			this.Status.CurrentMouseMoveMode = MouseMoveMode.Normal;
			this.Status.CurrentResizeState = ResizeState.None;
			setCursor(this.SelectedControl.Cursor);
			if ( mode == MouseMoveMode.Resize ) {
				this.Status.IsUserResizing = true;
				if ( resizestate == ResizeState.Left || resizestate == ResizeState.Top ||
					 resizestate == ResizeState.LeftTop ) {
					this.SelectedControl.Bounds = new Rectangle(
						this.SelectedControl.Left + change.Width,
						this.SelectedControl.Top + change.Height,
						this.SelectedControl.Width - change.Width,
						this.SelectedControl.Height - change.Height);
				} else if ( resizestate == ResizeState.LeftBottom ) {
					this.SelectedControl.Bounds = new Rectangle(
						this.SelectedControl.Left + change.Width,
						this.SelectedControl.Top,
						this.SelectedControl.Width - change.Width,
						this.SelectedControl.Height + change.Height);
				} else if ( resizestate == ResizeState.RightTop ) {
					this.SelectedControl.Bounds = new Rectangle(
						this.SelectedControl.Left,
						this.SelectedControl.Top + change.Height,
						this.SelectedControl.Width + change.Width,
						this.SelectedControl.Height - change.Height);
				} else {
					this.SelectedControl.Size = new Size(this.SelectedControl.Width + change.Width,
														 this.SelectedControl.Height + change.Height);
				}
			} else if ( mode == MouseMoveMode.Move ) {
				if ( this.Status.MouseOverCtrl != null && this.Status.MouseOverCtrl != this.SelectedControl &&
					 this.Status.MouseOverCtrl.IsContainer &&
					 this.Status.MouseOverCtrl != this.SelectedControl.Parent &&
					 noRecursion(this.SelectedControl, this.Status.MouseOverCtrl) ) {
					DesignerControl dcSel = this.SelectedControl;
					DesignerControl dcMO = this.Status.MouseOverCtrl;
					dcSel.BeginUpdate();
					Point loc = dcSel.GetPaintBounds().Location;
					loc.Offset(change.Width, change.Height);
					//if ( dcSel.Parent != null )
					//    dcSel.Parent.Controls.Remove(dcSel);
					//else if ( dcSel.DesignerViewControl != null )
					//    dcSel.DesignerViewControl.DesignerControls.Remove(dcSel);
					loc = dcMO.PointToDesignerControlClient(loc);
					if ( dcMO.IsDropAllowed(dcSel, loc, e.Button) ) {
						dcSel.Location = loc;
						dcMO.Controls.Add(dcSel);
					}
					dcSel.EndUpdate();
				} else if ( this.Status.MouseOverCtrl == null && this.SelectedControl.Parent != null &&
							noRecursion(this.SelectedControl, this.Status.MouseOverCtrl) ) {
					this.SelectedControl.BeginUpdate();
					Point loc = this.SelectedControl.GetPaintBounds().Location;
					loc.Offset(change.Width, change.Height);
					//this.SelectedControl.Parent.Controls.Remove(this.SelectedControl);
					if ( this.DesignerViewControl.IsDropAllowed(this.SelectedControl, loc, e.Button) ) {
						this.DesignerViewControl.AddDesignerControl(this.SelectedControl);
						this.SelectedControl.Location = loc;
					}
					this.SelectedControl.EndUpdate();
				} else {
					this.SelectedControl.BeginUpdate();
					Point loc = this.SelectedControl.Location;
					loc.Offset(change.Width, change.Height);
					this.SelectedControl.Location = loc;
					this.SelectedControl.EndUpdate();
				}
			//} else if ( mode == MouseMoveMode.DragDrop ) {
			//    this.SelectedControl.BeginUpdate();
			//    if ( this.Status.MouseOverCtrl != null &&
			//         this.Status.MouseOverCtrl.IsDropAllowed(this.Status.DragObject) )
			//        this.Status.MouseOverCtrl.DropObject(this.Status.DragObject);
			//    //Repaint();
			//    this.SelectedControl.EndUpdate();
			}
			_szChange = Size.Empty;
			this.Status.IsUserResizing = false;
		}

		protected static void dispose(object obj)
		{
			if ( obj == null )
				return;
			if ( obj is IDisposable ) {
				( (IDisposable)obj ).Dispose();
			}
			obj = null;
		}

		protected virtual void Repaint()
		{
			if ( bSuspendRepaint )
				return;

			if ( this.DesignerViewControl != null ) {
				this.DesignerViewControl.Refresh();
				//Debug.WriteLine("Refresh! " + DateTime.Now.ToString());
			}
		}

		protected Point ApplyZoomFactor(Point p)
		{
			Point point;
			if ( this.DesignerViewControl != null ) {
				float zoom = this.DesignerViewControl.ZoomFactor;
				if ( zoom != 1.0f )
					point = new Point((int)Math.Floor(p.X * zoom), (int)Math.Floor(p.Y * zoom));
				else
					point = p;
			} else {
				point = p;
			}
			return point;
		}
		protected Rectangle ApplyZoomFactor(Rectangle r)
		{
			Rectangle rect;
			if ( this.DesignerViewControl != null ) {
				float zoom = this.DesignerViewControl.ZoomFactor;
				if ( zoom != 1.0f )
					rect = new Rectangle((int)Math.Floor(r.X * zoom), (int)Math.Floor(r.Y * zoom), (int)Math.Ceiling(r.Width * zoom), (int)Math.Ceiling(r.Height * zoom));
				else
					rect = r;
			} else {
				rect = r;
			}
			return rect;
		}

		#endregion

		#region Locking
		protected object lockThis = new object();
		protected static object lockAll = new object();
		#endregion

		#endregion

		#region Private Members

		#region Variables

		private bool _bDisposed;

		private ResizeSides _resizeSidesAllowed;

		private DesignerControl _selectedCtrl;
		private Rectangle _bounds;
		private Rectangle _rectPaint;
		private Region _regionMouseOver;

		private GraphicsPath _pathSelection;
		private GraphicsPath _pathIndicator;

		private List<Rectangle> _rectsDisabledCorners;
		private List<Rectangle> _rectsAllowedCorners;
		private List<ResizeRectangle> _rectsResizeable;

		private Point _ptMouseDown;
		private Size _szChange;

		private Pen _selectionPen;
		private static Pen _cornerPen;
		private static SolidBrush _cornerDisabledBrush;
		private static SolidBrush _cornerEnabledBrush;

		private DesignerViewControl _designerView;

		#endregion

		#region Methods

		private void generateSymbolFrame()
		{
			if ( this.SelectedControl == null ) return;

			_bounds = this.SelectedControl.Bounds;
			_bounds.Inflate(OpenComposite.Base.Designer.View.Default.SelectionBoundsInflate);
			if ( this.SelectedControl.Parent != null ) {
				_rectPaint = this.SelectedControl.Parent.RectangleToDesignerView(_bounds);
			} else {
				_rectPaint = _bounds;
			}
			// evaluate mouse over region
			Rectangle r = _rectPaint;
			r.Inflate(-( OpenComposite.Base.Designer.View.Default.SelectionBoundsInflate.Width * 2 ), -( OpenComposite.Base.Designer.View.Default.SelectionBoundsInflate.Height * 2 ));
			_regionMouseOver = new Region(_rectPaint);
			_regionMouseOver.Exclude(r);

			Rectangle rectSelect = this.SelectedControl.Bounds;
			if ( this.SelectedControl.CanResize )
				rectSelect.Inflate(OpenComposite.Base.Designer.View.Default.SelectionInflate);

			if ( this.SelectedControl.Parent != null )
				rectSelect.Location = this.SelectedControl.Parent.PointToDesignerView(rectSelect.Location);
			int cornerW = OpenComposite.Base.Designer.View.Default.SelectionCornerSize.Width; // width and height of the corner rectangles
			int cornerpad = cornerW / 2;
			int x = rectSelect.X;
			int y = rectSelect.Y;
			int w = rectSelect.Width;
			int h = rectSelect.Height;

			// create selection path;
			if ( _pathSelection != null )
				dispose(_pathSelection);
			_pathSelection = new GraphicsPath();
			_pathSelection.AddRectangle(rectSelect);

			_rectsResizeable = getResizeRectangles(_resizeSidesAllowed, x, y, w, h, cornerpad, cornerW);
			if ( _rectsAllowedCorners == null )
				_rectsAllowedCorners = new List<Rectangle>();
			else
				_rectsAllowedCorners.Clear();
			if ( _rectsDisabledCorners == null )
				_rectsDisabledCorners = new List<Rectangle>();
			else
				_rectsDisabledCorners.Clear();
			foreach ( ResizeRectangle rrect in _rectsResizeable ) {
				if ( rrect.Disabled )
					_rectsDisabledCorners.Add(rrect.Rectangle);
				else
					_rectsAllowedCorners.Add(rrect.Rectangle);
			}
		}
		private void generateRouteFrame()
		{
			Route route = this.SelectedControl as Route;
			if ( _pathSelection != null )
				dispose(_pathSelection);
			_pathSelection = new GraphicsPath();
			if ( route == null )
				return;
			_pathSelection = route.RoutePath.Clone() as GraphicsPath;
		}

		private void generateIndicator()
		{
			Size min = this.SelectedControl.MinimumSize;
			Size max = this.SelectedControl.MaximumSize;
			GraphicsPath path = new GraphicsPath();
			Rectangle rect = this.SelectedControl.Bounds;
			ResizeState rstate = this.Status.CurrentResizeState;
			int width, height;
			bool isLeft, isTop;

			if ( this.SelectedControl.Parent != null )
				rect.Location = this.SelectedControl.Parent.PointToDesignerView(rect.Location);

			if ( this.Status.CurrentMouseMoveMode == MouseMoveMode.Resize ) {
				if ( _szChange.Width != 0 ) {
					isLeft = false;
					if ( rstate == ResizeState.Left || rstate == ResizeState.LeftBottom ||
						 rstate == ResizeState.LeftTop ) {
						width = rect.Width - _szChange.Width;
						isLeft = true;
					} else {
						width = rect.Width + _szChange.Width;
					}
					if ( !min.Equals(Size.Empty) && width < min.Width ) {
						width = min.Width;
						_szChange.Width = isLeft ? rect.Width - width : width - rect.Width;
					} else if ( !max.Equals(Size.Empty) && width > max.Width ) {
						width = max.Width;
						_szChange.Width = isLeft ? rect.Width - width : width - rect.Width;
					}

					if ( rstate == ResizeState.Left || rstate == ResizeState.LeftBottom ||
						 rstate == ResizeState.LeftTop ) {
						rect.X = rect.X + _szChange.Width;
					}
					rect.Width = width;
				}
				if ( _szChange.Height != 0 ) {
					isTop = false;
					if ( rstate == ResizeState.Top || rstate == ResizeState.LeftTop ||
						 rstate == ResizeState.RightTop ) {
						height = rect.Height - _szChange.Height;
						isTop = true;
					} else {
						height = rect.Height + _szChange.Height;
					}
					if ( !min.Equals(Size.Empty) && height < min.Height ) {
						height = min.Height;
						_szChange.Height = isTop ? rect.Height - height : height - rect.Height;
					} else if ( !max.Equals(Size.Empty) && height > max.Height ) {
						height = max.Height;
						_szChange.Height = isTop ? rect.Height - height : height - rect.Height;
					}

					if ( rstate == ResizeState.Top || rstate == ResizeState.LeftTop ||
						 rstate == ResizeState.RightTop ) {
						rect.Y = rect.Y + _szChange.Height;
					}
					rect.Height = height;
				}
				//rect.Inflate(View.Default.SelectionInflate);
			} else if ( this.DesignerViewControl.Status.CurrentMouseMoveMode == MouseMoveMode.Move ) {
				rect.Offset(_szChange.Width, _szChange.Height);
			}
			if ( _pathIndicator != null ) {
				_pathIndicator.Reset();
				_pathIndicator.AddRectangle(rect);
			}
		}

		private bool noRecursion(DesignerControl dc, DesignerControl current)
		{
			if ( current == null )
				return true;
			else if ( dc == current.Parent )
				return false;
			else if ( current.Parent == null )
				return true;
			else
				return noRecursion(dc, current.Parent);
		}
		private void setCursor(ResizeState state)
		{
			if ( state == ResizeState.Left || state == ResizeState.Right )
				setCursor(Cursors.SizeWE);
			else if ( state == ResizeState.Top || state == ResizeState.Bottom )
				setCursor(Cursors.SizeNS);
			else if ( state == ResizeState.LeftTop || state == ResizeState.RightBottom )
				setCursor(Cursors.SizeNWSE);
			else if ( state == ResizeState.LeftBottom || state == ResizeState.RightTop )
				setCursor(Cursors.SizeNESW);
			else
				setCursor(Cursors.Default);
		}
		private void setCursor(Cursor cur)
		{
			if ( this.DesignerViewControl.InvokeRequired ) {
				setControlProperty(this.DesignerViewControl, "Cursor", cur);
			} else {
				this.DesignerViewControl.Cursor = cur;
			}
		}

		private List<ResizeRectangle> getResizeRectangles(ResizeSides sides, int x, int y, int w, int h, int cp, int cw)
		{
			int xl = x - cp;
			int xm = x + ( w / 2 ) - cp;
			int xr = x + w - cp;
			int yt = y - cp;
			int ym = y + ( h / 2 ) - cp;
			int yb = y + h - cp;

			List<ResizeRectangle> rects = new List<ResizeRectangle>();
			if ( this.SelectedControl.CanResize ) {
				rects.Add(new ResizeRectangle(
					ResizeState.Left,
					( sides & ResizeSides.Left ) == 0,
					new Rectangle(xl, ym, cw, cw)));
				rects.Add(new ResizeRectangle(
					ResizeState.Right,
					( sides & ResizeSides.Right ) == 0,
					new Rectangle(xr, ym, cw, cw)));
				rects.Add(new ResizeRectangle(
					ResizeState.Top,
					( sides & ResizeSides.Top ) == 0,
					new Rectangle(xm, yt, cw, cw)));
				rects.Add(new ResizeRectangle(
					ResizeState.Bottom,
					( sides & ResizeSides.Bottom ) == 0,
					new Rectangle(xm, yb, cw, cw)));
			}
			rects.Add(new ResizeRectangle(
				ResizeState.LeftTop,
				( sides & ( ResizeSides.Left | ResizeSides.Top ) ) != ( ResizeSides.Left | ResizeSides.Top ),
				new Rectangle(xl, yt, cw, cw)));
			rects.Add(new ResizeRectangle(
				ResizeState.LeftBottom,
				( sides & ( ResizeSides.Left | ResizeSides.Bottom ) ) != ( ResizeSides.Left | ResizeSides.Bottom ),
				new Rectangle(xl, yb, cw, cw)));
			rects.Add(new ResizeRectangle(
				ResizeState.RightTop,
				( sides & ( ResizeSides.Right | ResizeSides.Top ) ) != ( ResizeSides.Right | ResizeSides.Top ),
				new Rectangle(xr, yt, cw, cw)));
			rects.Add(new ResizeRectangle(
				ResizeState.RightBottom,
				( sides & ( ResizeSides.Right | ResizeSides.Bottom ) ) != ( ResizeSides.Right | ResizeSides.Bottom ),
				new Rectangle(xr, yb, cw, cw)));
			return rects;
		}

		private delegate void SetValueDelegate(Object obj, Object val, Object[] index);
		private void setControlProperty(Control ctrl, String propName, Object val)
		{
			PropertyInfo propInfo = ctrl.GetType().GetProperty(propName);
			Delegate dgtSetValue = new SetValueDelegate(propInfo.SetValue);
			ctrl.Invoke(dgtSetValue, new Object[3] { ctrl, val, /*index*/null });
		}

		#endregion

		#region Event Handlers

		private void _selectedControl_LocationChanged(object sender, EventArgs e)
		{
			if ( _selectedCtrl is Route )
				generateRouteFrame();
			else
				generateSymbolFrame();
		}
		private void _selectedControl_SizeChanged(object sender, EventArgs e)
		{
			if ( _selectedCtrl is Route )
				generateRouteFrame();
			else
				generateSymbolFrame();
		}
		private void _selectedCtrl_ParentChanged(object sender, EventArgs e)
		{
			if ( _selectedCtrl is Route )
				generateRouteFrame();
			else
				generateSymbolFrame();
		}
		private void _selectedCtrl_Removed(object sender, EventArgs e)
		{
			_selectedCtrl = null;
		}


		#endregion

		#endregion

	}

	[Flags]
	public enum ResizeSides
	{
		None = 0,
		Left = 1,
		Right = 2,
		Top = 4,
		Bottom = 8,
		All = ResizeSides.Left | ResizeSides.Right | ResizeSides.Top | ResizeSides.Bottom
	}
	public enum ResizeState
	{
		None = 0,
		Left,
		Right,
		Top,
		Bottom,
		LeftTop,
		LeftBottom,
		RightTop,
		RightBottom
	}
	internal struct ResizeRectangle
	{
		public ResizeRectangle(ResizeState state, bool disabled, Rectangle rect)
		{
			this.Disabled = disabled;
			this.State = state;
			this.Rectangle = rect;
		}
		public bool Disabled;
		public ResizeState State;
		public Rectangle Rectangle;
	}
}
